package com.coincalf.admin.service.impl;

import com.baomidou.mybatisplus.mapper.SqlHelper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.coincalf.admin.dto.AuditDTO;
import com.coincalf.admin.dto.CoinWithdrawalsCountDTO;
import com.coincalf.admin.entity.*;
import com.coincalf.admin.mapper.CoinWithdrawMapper;
import com.coincalf.admin.service.*;
import com.coincalf.framework.constants.Constant;
import com.coincalf.framework.enums.*;
import com.coincalf.framework.exception.AccountException;
import com.coincalf.framework.exception.CoincalfException;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 虚拟币提现 服务实现类
 * </p>
 *
 * @author Haliyo
 * @since 2018-05-17
 */
@Service
@Slf4j
public class CoinWithdrawServiceImpl extends ServiceImpl<CoinWithdrawMapper, CoinWithdraw> implements CoinWithdrawService, Constant {

    @Autowired
    private CoinWithdrawAuditRecordService coinWithdrawAuditRecordService;
    @Autowired
    private UserService userService;
    @Autowired
    private MultiLevelAuditService multiLevelAuditService;
    @Autowired
    private LockService lockService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private AccountService accountService;


    @Override
    public Page<CoinWithdraw> selectListPage(Page<CoinWithdraw> page, Wrapper<CoinWithdraw> wrapper) {
        wrapper = (Wrapper<CoinWithdraw>) SqlHelper.fillWrapper(page, wrapper);
        page.setRecords(baseMapper.selectListPage(page, wrapper));
        return page;
    }

    /**
     * 提币审核
     *
     * @param auditDTO 提币审核请求参数
     * @param sysUser  当前登录用户
     * @throws CoincalfException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void coinWithdrawAudit(AuditDTO auditDTO, SysUser sysUser) throws CoincalfException {
        log.info("提币审核：coinWithdrawAudit auditDTO:" + auditDTO);
        // 校验权限
        if (!multiLevelAuditService.coinWithdrawPermissionCheck(auditDTO.getId(), sysUser)) {
            throw new CoincalfException("审核权限不足");
        }
        boolean isLocked = false;
        try {
            // 通过内存锁防止重复提交审核，导致资金异常
            isLocked = lockService.getLock(REDIS_KEY_COIN_WITHDRAW_AUDIT_LOCK, String.valueOf(auditDTO.getId()), false);
            if (!isLocked) {
                throw new CoincalfException("已经提交审核，请勿重复操作");
            }
            CoinWithdraw coinWithdraw = baseMapper.selectById(auditDTO.getId());
            if (coinWithdraw == null) {
                throw new CoincalfException("提现订单不存在");
            }
            if (coinWithdraw.getStatus() != CoinWithdrawStatus.PENDING.getCode()) {
                throw new CoincalfException("此记录已审核");
            }
            // 审核轨迹
            CoinWithdrawAuditRecord cashRechargeAuditRecord = new CoinWithdrawAuditRecord();
            cashRechargeAuditRecord.setOrderId(auditDTO.getId())
                    .setStatus(auditDTO.getStatus())
                    .setRemark(auditDTO.getRemark())
                    .setStep(coinWithdraw.getStep())
                    .setAuditUserId(sysUser.getId())
                    .setAuditUserName(sysUser.getFullname())
                    .setCreated(new Date());
            coinWithdrawAuditRecordService.insert(cashRechargeAuditRecord);
            User user = userService.selectById(coinWithdraw.getUserId());
            // 更新提现申请单状态
            coinWithdraw.setRemark(auditDTO.getRemark());
            if (auditDTO.getStatus() == CoinWithdrawStatus.REFUSE.getCode()) {
                // 审核拒绝
                coinWithdraw.setStatus(CoinWithdrawStatus.REFUSE.getCode())
                        .setMum(BigDecimal.ZERO)
                        .setAuditTime(new Date());
                baseMapper.updateById(coinWithdraw);
                // 解冻资金账户
                accountService.unlockAmount(
                        coinWithdraw.getUserId(),
                        coinWithdraw.getCoinId(),
                        coinWithdraw.getNum(),
                        BusinessType.WITHDRAW,
                        coinWithdraw.getId()
                );
                return;
            }
            // 审核通过
            Config config = configService.queryByCodeAndType(CONFIG_TYPE_SYSTEM, Constant.CONFIG_COIN_WITHDRAW_AUDIT_STEPS);
            if (config == null || Strings.isNullOrEmpty(config.getValue())) {
                throw new CoincalfException("没有配置审核级数");
            }
            int step = coinWithdraw.getStep();
            if (step == Integer.parseInt(config.getValue())) {
                // 最终审核通过
                coinWithdraw.setStatus(CoinWithdrawStatus.PASSED.getCode());
                coinWithdraw.setAuditTime(new Date());
                baseMapper.updateById(coinWithdraw);
                // 变更账户资金
                this.withAmount(coinWithdraw, user.getId());
                return;
            }
            // 不是最终审核，审计级别加一级，状态为待审核
            coinWithdraw.setStatus(CoinWithdrawStatus.PENDING.getCode()).setStep(step + 1);
            baseMapper.updateById(coinWithdraw);
        } catch (AccountException e) {
            throw new CoincalfException(e.getMessage());
        } finally {
            // 释放锁
            if (isLocked) {
                lockService.unlock(REDIS_KEY_COIN_WITHDRAW_AUDIT_LOCK, String.valueOf(auditDTO.getId()));
            }
        }
    }

    /**
     * 数字货币提现审核通过，修改资金账户
     *
     * @param coinWithdraw 提现申请单
     * @param userId       登录用户ID
     * @return
     */
    private boolean withAmount(CoinWithdraw coinWithdraw, Long userId) {
        //USDT只取OMNI
        if (coinWithdraw.getCoinId() == 4 || coinWithdraw.getCoinId() == 6) {
            coinWithdraw.setCoinId(2L);
        }
        Account account = accountService.queryByUserIdAndCoinId(userId, coinWithdraw.getCoinId());
        if (account == null) {
            log.error("资金账户异常：userId：{}，coinId：{}", userId, coinWithdraw.getCoinId());
            throw new AccountException("资金账户异常");
        }
        User adminUser = userService.queryAdminUser(AdminUserType.ADMIN);
        if (adminUser == null) {
            log.error("尚未配置管理员用户");
            throw new AccountException("尚未配置管理员用户");
        }
        // 解冻资金账户
        accountService.unlockAmount(userId,
                coinWithdraw.getCoinId(),
                coinWithdraw.getNum(),
                BusinessType.WITHDRAW,
                coinWithdraw.getId());
        // 扣减提现手续费
        accountService.transferAmount(userId,
                adminUser.getId(),
                coinWithdraw.getCoinId(),
                coinWithdraw.getFee(),
                BusinessType.WITHDRAW_FEE,
                coinWithdraw.getId(),
                BusinessType.WITHDRAW_FEE.getDesc());
        // 扣减实际提现数量
        accountService.subtractAmount(userId,
                coinWithdraw.getCoinId(),
                coinWithdraw.getMum(),
                BusinessType.WITHDRAW,
                BusinessType.WITHDRAW.getDesc(),
                coinWithdraw.getId());
        return true;
    }

    public Page<CoinWithdrawalsCountDTO> selectCountMain(Page<CoinWithdrawalsCountDTO> page, Map<String, Object> paramMap) {
        return page.setRecords(baseMapper.selectCountMain(page, paramMap));
    }

    @Override
    public List<CoinWithdrawalsCountDTO> selectValidCounts(Map<String, Object> paramMap) {
        return baseMapper.selectValidCounts(paramMap);
    }

    @Override
    public List<CoinWithdrawalsCountDTO> selectUserCt(Map<String, Object> paramMap) {
        return baseMapper.selectUserCt(paramMap);
    }

}
